package com.yeskery.nut.bean.padding;

import com.yeskery.nut.annotation.environment.Value;
import com.yeskery.nut.bean.BeanException;
import com.yeskery.nut.bind.BindObject;
import com.yeskery.nut.bind.FitValueHelper;
import com.yeskery.nut.core.Environment;
import com.yeskery.nut.core.InputStreamResource;
import com.yeskery.nut.util.ExpressionUtils;
import com.yeskery.nut.util.ResourceUtils;
import com.yeskery.nut.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;

/**
 * Value注解属性填充对象
 * @author sprout
 * @version 1.0
 * 2022-07-09 15:08
 */
public class ValueAttributePadding extends AbstractAttributePadding {

    /** 环境对象 */
    private final Environment environment;

    /**
     * 构建Value注解属性填充对象
     * @param environment 环境对象
     */
    public ValueAttributePadding(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void padding(Object object, Field[] fields) {
        for (Field field : fields) {
            Value annotation = field.getAnnotation(Value.class);
            String expression = annotation.value().trim();
            if (StringUtils.isEmpty(expression)) {
                continue;
            }
            if (paddingResourceField(object, field, expression)) {
                continue;
            }
            if (FitValueHelper.getInstance().isBasicTypeClass(field.getType())) {
                String value = ExpressionUtils.getExpressValue(environment, expression,
                        () -> new BeanException("Bean's Attribute [" + field.getType().getName() + "] Name ["
                                + field.getName() + "] @Value Annotation Expression [" + expression + "] Not Exist."));
                BindObject bindObject = FitValueHelper.getInstance().getFitParamValue(field.getName(), value, field.getType());
                if (!bindObject.isEmpty()) {
                    try {
                        setObjectFileValue(object, field, bindObject.getData());
                    } catch (Exception e) {
                        throw new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name [" + field.getName() + "] Padding Fail.", e);
                    }
                }
            } else {
                if (field.getType().isArray()) {
                    try {
                        Object array = ExpressionUtils.getExpressArray(environment, expression, field,
                                () -> new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name ["
                                        + field.getName() + "] @Value Annotation Expression [" + expression + "] Invalid."));
                        if (array != null) {
                            setObjectFileValue(object, field, array);
                        }
                    } catch (Exception e) {
                        throw new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name [" + field.getName() + "] Padding Fail.", e);
                    }
                } else if (Collection.class.isAssignableFrom(field.getType())) {
                    try {
                        Collection<Object> collection = ExpressionUtils.getExpressCollection(environment, expression, field,
                                () -> new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name ["
                                        + field.getName() + "] @Value Annotation Expression [" + expression + "] Invalid."));
                        if (collection != null) {
                            setObjectFileValue(object, field, collection);
                        }
                    } catch (Exception e) {
                        throw new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name [" + field.getName() + "] Padding Fail.", e);
                    }
                } else if (Map.class.isAssignableFrom(field.getType())) {
                    try {
                        Map<String, Object> map = ExpressionUtils.getExpressMap(environment, expression, field,
                                () -> new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name ["
                                        + field.getName() + "] @Value Annotation Expression [" + expression + "] Invalid."));
                        if (map != null) {
                            setObjectFileValue(object, field, map);
                        }
                    } catch (Exception e) {
                        throw new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name [" + field.getName() + "] Padding Fail.", e);
                    }
                } else {
                    throw new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name [" + field.getName() + "] Not Support.");
                }
            }
        }
    }

    /**
     * 填充资源属性
     * @param object 对象
     * @param field 需要处理的字段
     * @param expression 资源表达式
     * @return 是否成功填充
     */
    private boolean paddingResourceField(Object object, Field field, String expression) {
        if (ResourceUtils.isSupport(expression)) {
            InputStreamResource resource = ResourceUtils.getInputStreamResource(expression);
            if (!field.getType().isAssignableFrom(resource.getClass())) {
                throw new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name ["
                        + field.getName() + "] @Value Annotation Expression [" + expression
                        + "] Not Match. Actual Type Is [" + resource.getClass().getName() + "]");
            }
            try {
                setObjectFileValue(object, field, resource);
                return true;
            } catch (Exception e) {
                throw new BeanException("Bean's Attribute [ " + field.getType().getName() + "] Name [" + field.getName() + "] Padding Fail.", e);
            }
        }
        return false;
    }
}
